/************************************************************************************
* CollectorView.cpp                                                                 *
*                                                                                   *
* Copyright (C) 2011 Varuna L Amachi                                                *
*                                                                                   *
* This program is free software; you can redistribute it and/or modify              *
* it under the terms of the GNU General Public License as published by              *
* the Free Software Foundation; either version 2 of the License, or any             *
* later version.                                                                    *
*                                                                                   *
* This program is distributed in the hope that it will be useful, but               *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY        *
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for       *
* more details. You should have received a copy of the GNU General Public           *
* License along with this program; if not, write to the Free Software Foundation,   *
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                       *
*                                                                                   *
*************************************************************************************/
#include "CollectorView.h"
#include "common/SizeConstants.h"
#include "CollectorSortFilter.h"
#include "Types.h"
#include "CollectorDelegate.h"

#include <QVBoxLayout>
#include <QHeaderView>
#include <QScrollBar>
#include <QLabel>
#include <QModelIndexList>
#include <QLabel>
#include <QAction>
#include <QMenu>
#include <QFileDialog>
#include <QDesktopServices>
#include <QContextMenuEvent>
#include <QRadioButton>
#include <QButtonGroup>


QString CollectorView::NAME = "Audio";

using namespace Yamp;

CollectorView::CollectorView(YContext* context,
                     QWidget *parent) :
    YampComponent(context, parent),
//    m_tableView(new QTableView()),
    m_view(new QTreeView()),
    m_loader(new FileSystemCollectionLoader(this)),
    m_filter(new SearchBox(this)),
    m_proxyModel(new CollectorSortFilter(this))
{

    m_model = Collector::get();

    m_filterByArtist= new QCheckBox("Artist", this);
    m_filterByAlbum = new QCheckBox("Album", this);
    m_filterByTitle = new QCheckBox("Title", this);
    m_menuButton    = new QToolButton(this);
    m_ruleOneLabel  = new QLabel("  OR   ");
    m_ruleTwoLabel  = new QLabel("  OR   ");
    m_menuButton->setText("Menu");

    m_andButton = new QRadioButton("And", this);
    m_orButton  = new QRadioButton("Or", this);

    m_progress = new QProgressBar(this);
    m_status = new QLabel(this);
    m_proxyModel->setSourceModel(m_model);
    m_proxyModel->setDynamicSortFilter(true);



    setupUi();
    setupActions();
    setupConnections();
    context->player()->addListener(this);
    m_proxyModel->sort(2);
}


void CollectorView::setupUi() {
    m_progress->hide();
    m_status->hide();

    CollectorDelegate* delegate = new CollectorDelegate(this);
    m_view->setItemDelegate(delegate);
    this->setAutoFillBackground(true);
//    m_view->setStyleSheet("selection-background-color:	#002626;"
//            "selection-color: green;"
//            "background-color: #FFFAF5;"
//            "alternate-background-color:#FFF5EB;"
//            "color: #002933");
    m_view->setModel(m_proxyModel);
    m_view->setSelectionMode(QAbstractItemView::ExtendedSelection);

    m_view->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_view->setSortingEnabled(true);
    m_view->setWordWrap(false);
    m_view->setFocusPolicy(Qt::WheelFocus);
    m_view->setAutoScroll(true);
    m_view->header()->setResizeMode(1, QHeaderView::Stretch);
    m_view->header()->setResizeMode(2, QHeaderView::Stretch);
    m_view->header()->setResizeMode(3, QHeaderView::Stretch);
    m_view->setColumnWidth(4, 16);
    m_view->header()->setStretchLastSection(false);

    m_view->hideColumn(0);
    m_view->verticalScrollBar()->setAutoFillBackground(true);
    m_view->setFont(QFont(m_view->font().defaultFamily(), 9));
    m_view->setEditTriggers(QAbstractItemView::CurrentChanged);

    m_filterByArtist->setCheckable(true);
    m_filterByArtist->setToolTip(tr("Filter by artist"));

    m_filterByAlbum->setCheckable(true);
    m_filterByAlbum->setToolTip(tr("Filter by album"));

    m_filterByTitle->setCheckable(true);
    m_filterByTitle->setToolTip(tr("Filter by title"));

    QButtonGroup* buttonGroup = new QButtonGroup(this);
    buttonGroup->addButton(m_andButton);
    buttonGroup->addButton(m_orButton);

    QVBoxLayout* mainLayout = new QVBoxLayout();
    QHBoxLayout* upperLayout= new QHBoxLayout();
    QVBoxLayout* leftLayout = new QVBoxLayout();
    QHBoxLayout* leftUpper = new QHBoxLayout();
    QHBoxLayout* leftLower = new QHBoxLayout();

    leftUpper->addWidget(new QLabel(" Filter "));
    leftUpper->addWidget(m_filter);
    leftLayout->addLayout(leftUpper);

    leftLower->addWidget(new QLabel(" By : "));
    leftLower->addWidget(m_filterByTitle);
    leftLower->addWidget(m_ruleOneLabel);
    leftLower->addWidget(m_filterByArtist);
    leftLower->addWidget(m_ruleTwoLabel);
    leftLower->addWidget(m_filterByAlbum);
    leftLower->addStretch(10);
    leftLower->addWidget(new QLabel("   Rule : "));
    leftLower->addWidget(m_andButton);
    leftLower->addWidget(m_orButton);
    leftLower->addStretch(10);
    m_orButton->setChecked(true);
    leftLayout->addLayout(leftLower);

    upperLayout->addLayout(leftLayout);
    upperLayout->addWidget(m_menuButton);

    QHBoxLayout *statusLayout = new QHBoxLayout();
    statusLayout->addWidget(m_status);
    statusLayout->addWidget(m_progress);

    mainLayout->addLayout(upperLayout);
    mainLayout->addWidget(m_view);
    mainLayout->addLayout(statusLayout);
    setLayout(mainLayout);
    m_view->setAlternatingRowColors(true);
}

void CollectorView::setupConnections() {
    connect(m_filterByArtist, SIGNAL(clicked()), this, SLOT(filterChanged()));
    connect(m_filterByAlbum, SIGNAL(clicked()), this, SLOT(filterChanged()));
    connect(m_filterByTitle, SIGNAL(clicked()), this, SLOT(filterChanged()));
    connect(m_loader, SIGNAL(finishedLoading(QList<CollectorItem*>*)),
            this, SLOT(finishedLoading(QList<CollectorItem*>*)));
    connect(m_view, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(addAndPlay()));
    connect(m_filter, SIGNAL(textChanged(QString)), m_proxyModel, SLOT(setExpression(QString)));
    connect(m_andButton, SIGNAL(clicked()), this, SLOT(andRuleActivated()));
    connect(m_orButton, SIGNAL(clicked()), this, SLOT(orRuleActivated()));

    connect(m_loader, SIGNAL(loadingStarted(int)), this, SLOT(itemLoadingStarted(int)));
    connect(m_loader, SIGNAL(progress(int,QString)), m_progress, SLOT(setValue(int)));
    connect(m_model, SIGNAL(collectionDeletionEnded()), this, SLOT(onCollectionDeletionComplete()));
}

void CollectorView::setupActions() {
    m_actAddToPlaylist = new QAction(tr("Add to playlist"), this);
    m_actAddToPlaylist->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus));
    connect(m_actAddToPlaylist , SIGNAL(triggered()), this, SLOT(addToPlaylist()));

    m_actRemove = new QAction(tr("Remove from collection"), this);
    connect(m_actRemove, SIGNAL(triggered()), this, SLOT(removeFromCollection()));

    m_actAddDir = new QAction(tr("Add a directory"), this);
    connect(m_actAddDir, SIGNAL(triggered()), this, SLOT(addDirectory()));

    m_actAddFiles = new QAction(tr("Add files"), this);
    connect(m_actAddFiles, SIGNAL(triggered()), this, SLOT(addFiles()));

    m_actAddArtist = new QAction(tr("Add all from Artist(s)"), this);
    connect(m_actAddArtist, SIGNAL(triggered()), this, SLOT(onAddArtist()));

    m_actAddAlbum = new QAction(tr("Add all from album(s)"), this);
    connect(m_actAddAlbum, SIGNAL(triggered()), this, SLOT(onAddAlbum()));

    QMenu* menu = new QMenu(this);
    menu->addAction(m_actAddToPlaylist);
    menu->addAction(m_actAddArtist);
    menu->addAction(m_actAddAlbum);
    menu->addSeparator();
    menu->addAction(m_actAddDir);
    menu->addAction(m_actAddFiles);
    menu->addAction(m_actRemove);
    m_menuButton->setPopupMode(QToolButton::InstantPopup);
    m_menuButton->setMenu(menu);
}


QString CollectorView::name() {
    return CollectorView::NAME;
}


void CollectorView::itemLoadingStarted(int numItemsToLoad) {
    m_status->setVisible(true);
    m_status->setText("Loading....");
    m_progress->setRange(0, numItemsToLoad);
    m_progress->setVisible(true);
}

void CollectorView::finishedLoading(QList<CollectorItem*>* items) {
    m_model->add(items);
    m_model->setValid(true);
    m_proxyModel->sort(2);
    m_loader->clear();
    m_status->setVisible(false);
    m_progress->setVisible(false);
}


void CollectorView::addToPlaylist() {
    QModelIndexList indices = m_view->selectionModel()->selectedRows(0);
    if(indices.empty()) {
        return;
    }
    else if(indices.size() == 1) {
        MediaItem* item = m_model->item(indices.at(0).data().toString());
        m_context->playlist()->append(item, false);
    }
    else {
        foreach(QModelIndex index, indices) {
            MediaItem* item = m_model->item(index.data().toString());
            m_context->playlist()->append(item, false);
        }
    }
}


void CollectorView::addAndPlay() {
    QModelIndexList indices = m_view->selectionModel()->selectedRows(0);
    if(indices.empty()) {
        return;
    }
    MediaItem* item = m_model->item(indices.at(0).data().toString());
    m_context->playlist()->append(item, true);
}


void CollectorView::contextMenuEvent(QContextMenuEvent *event) {
    QMenu menu(this);
    menu.addAction(m_actAddToPlaylist);
    menu.addAction(m_actAddArtist);
    menu.addAction(m_actAddAlbum);
    menu.addSeparator();
    menu.addAction(m_actAddDir);
    menu.addAction(m_actAddFiles);
    menu.addAction(m_actRemove);
    menu.exec(event->globalPos());
}


void CollectorView::playStarted(MediaItem* item) {
    m_model->itemPlayed(item);
}

void CollectorView::finished(MediaItem* item) {
    m_model->itemFinishedPlaying(item);
}

void CollectorView::selected(MediaItem* source) {
    //Not applicable
}

void CollectorView::playlistChanged() {
    //Not applicable
}

void CollectorView::playlistCleared() {
    //Not applicable
}


void CollectorView::removeFromCollection() {
    QModelIndexList indices = m_view->selectionModel()->selectedRows(0);
    QList<QString> *remIds = new QList<QString>();
    foreach(QModelIndex index, indices) {
        remIds->append(index.data().toString());
    }
    m_model->remove(remIds);
}



void CollectorView::filterChanged() {
    int filter = 0;
    if(m_filterByTitle->isChecked()) {
        filter |= FC_Title;
    }
    if(m_filterByArtist->isChecked()) {
        filter |= FC_Artist;
    }
    if(m_filterByAlbum->isChecked()) {
        filter |= FC_Album;
    }
    m_proxyModel->setFilterCriteria(filter);
}


void CollectorView::andRuleActivated() {
    m_ruleOneLabel->setText("  AND  ");
    m_ruleTwoLabel->setText("  AND  ");
    m_proxyModel->setFilterRule(AndRule);
}


void CollectorView::orRuleActivated() {
    m_ruleOneLabel->setText("  OR   ");
    m_ruleTwoLabel->setText("  OR   ");
    m_proxyModel->setFilterRule(OrRule);
}


void CollectorView::addDirectory() {
    QString dirName = QFileDialog::getExistingDirectory(this, "Add Folder",
                            QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
    QList<QUrl>* list = new QList<QUrl>;
    list->append(QUrl::fromLocalFile(dirName));
    m_loader->load(list);
}


void CollectorView::addFiles() {
    QStringList files = QFileDialog::getOpenFileNames(this, tr("Select Music Files"),
              QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
    if(! files.empty()) {
        QList<QUrl>* urls = new QList<QUrl>();
        foreach(QString fileName, files) {
            urls->append(QUrl::fromLocalFile(fileName));
        }
        m_loader->load(urls);
    }
}



void CollectorView::ratingChanged(MediaItem *item, MediaRating rating) {
    m_model->mediaRatingChanged(dynamic_cast<CollectorItem*>(item), rating);
    m_view->repaint(); //I dont know how else can I do this
}


Collector* CollectorView::model() {
    return m_model;
}

void CollectorView::onAddArtist() {
    QModelIndexList indices = m_view->selectionModel()->selectedRows(2);
    if(indices.empty()) {
        return;
    }
    QSet<QString> selectedArtists;
    QList<CollectorItem *> items;
    foreach(QModelIndex index, indices) {
        QString artist = index.data().toString();
        if(! selectedArtists.contains(artist)) {
            selectedArtists.insert(artist);
            m_model->itemsFromArtist(artist, items);
        }
    }
    foreach(CollectorItem *colItem, items) {
        m_context->playlist()->append(dynamic_cast<MediaItem *>(colItem), false);
    }
}

void CollectorView::onAddAlbum() {
    QModelIndexList albumIndices = m_view->selectionModel()->selectedRows(3);
    QModelIndexList artistIndices = m_view->selectionModel()->selectedRows(2);
    if(albumIndices.empty()) {
        return;
    }
    QSet<QString> selectedAlbum;
    QList<CollectorItem *> items;
    for(int i = 0; i < albumIndices.size(); ++i) {
        QModelIndex index = albumIndices.at(i);
        QString album = index.data().toString();
        if(! selectedAlbum.contains(album)) {
            QString artist = artistIndices.at(i).data().toString();
            selectedAlbum.insert(album);
            m_model->itemsFromAlbum(album, artist, items);
        }
    }
    foreach(CollectorItem *colItem, items) {
        m_context->playlist()->append(dynamic_cast<MediaItem *>(colItem), false);
    }
}


void CollectorView::varifyActionValidity() {

}


void CollectorView::onCollectionDeletionComplete() {
    m_view->repaint();
}
